import AbstractMap from './AbstractMap'
import { featureGroup, geoJSON, map as createMap } from 'leaflet'
import Layer from './layers/Layer'
import Marker from './markers/Marker'
import Toolkit from './Toolkit'
import Store from './Store'
/**
 * @classdesc  地图封装
 * @param {HTMLElement | string} el - 地图container。
 * @param {Object} options - 参数。
 * @author Niyang
 */
export default class WebMap extends AbstractMap {
    constructor (el, options) {
        super()
        this.map = null
        this.layer = null
        this.marker = null
        this.features = null
        this.store = null
        this.build(el, options)
    }

    /**
     * @description 创建地图
     * @param {*} el
     * @param {*} options
     * @returns Map
     */
    build (el, options) {
        const LAYERS = 'layers'
        const cfg = Toolkit.assign({}, options)
        if (Toolkit.has(options, LAYERS)) {
            cfg[LAYERS] = Toolkit.ensure(options[LAYERS]).map(cfg => this.buildLayer(cfg)).filter(layer => layer !== null)
        }
        this.map = createMap(el, cfg)
        this.store = new Store()
    }

    /**
     * @description 地图加载完后回调
     * @param {Function} callback
     */
    whenReady (callback) {
        this.map.whenReady(callback, this)
    }

    /**
     * @description 浏览器窗口改变，手动刷新地图
     * @param {Object|Boolean} cfg
     */
    resize (cfg) {
        this.map.invalidateSize(cfg)
    }

    /**
     * @description 是否含有某个Layer
     * @param {Layer} layer
     * @returns true or false
     */
    has (layer) {
        return this.map.hasLayer(layer)
    }

    /**
     * @description 创建Layer
     * @param {Object} options
     * @param {string} [options.type] Layer类型此项是必须的
     * @param {string} [options.url] Layer加载地址
     * @param {string} [options.layerID] LayerId
     * @returns Layer
     */
    buildLayer (options) {
        return this._helpLayer().getLayer(options)
    }

    /**
     * @description 创建Maker
     * @param {Object} options
     *  @param {string} [options.symbol] Marker类型此项是必须的
     * @param {string} [options.latlng] Marker经纬度
     * @param {Object}[options.options] Marker配置项
     * @returns Marker
     */
    buildMarker (options) {
        return this._helpMarker().getMarker(options)
    }

    /**
     * @description 添加Layer到地图
     * @param {Layer} layer
     */
    addLayer (layer) {
        layer.addTo(this.map)
    }

    /**
     * @description 获取Layer通过Id
     * @param {String} id
     * @returns Layer
     */
    getLayer (id) {
        return this.features.getLayer(this.store.get(id))
    }

    /**
     * @description 移除Layer
     * @param {Layer} layer
     */
    removeLayer (layer) {
        if (this.has(layer)) {
            this.map.removeLayer(layer)
        }
    }

    /**
     * @description 添加特征Layer
     * @param {Layer} layer
     * @param {Boolean} only
     */
    addFeatureLayer (layer, only) {
        if (Toolkit.isNull(this.features)) {
            this.features = this._createFeatureGroup().addTo(this.map)
        }
        if (only) {
            this.clearFeatureLayers()
        }
        this.features.addLayer(layer)
    }

    /**
     * @description 移除Layer
     * @param {Layer} layer
     */
    removeFeatureLayer (layer) {
        if (this.features && this.features.hasLayer(layer)) {
            this.features.removeLayer(layer)
        }
    }

    /**
     * @description 清除FeatureLayer
     */
    clearFeatureLayers () {
        this.features.clearLayers()
    }

    /**
     * @description 获取特征Layer
     * @returns Feature
     */
    getFeature () {
        return this.features
    }

    /**
     * @description 获取缩放
     * @returns Number
     */
    getZoom () {
        return this.map.getZoom()
    }

    /**
     * @description 获取Layer
     * @param {Object} feature
     * @param {Object} options
     * @returns Layer
     */
    getLayerFromGeoJSON (feature, options) {
        return geoJSON(feature, options)
    }

    /**
     * @description 获取所有的特征Layer
     * @returns Array<Layer>
     */
    getFeatureLayers () {
        return Toolkit.isNull(this.features) ? [] : this.features.getLayers()
    }

    /**
     * @description 获取最新添加的Layer
     * @returns Layer
     */
    getLatestFeatureLayer () {
        const layers = this.getFeatureLayers()
        return layers.length === 0 ? null : layers[layers.length - 1]
    }

    /**
     * @description 适配到某个边界
     * @example
     *        fitBounds(layer.getBounds(),{zoom:18})
     * @param {Layer.bounds} bounds
     * @param {Object} options
     */
    fitBounds (bounds, options) {
        this.map.fitBounds(bounds, options)
    }

    /**
     * @description
     * @param {Array<number>} center
     * @param {Number} zoom
     * @param {Object} options
     */
    setView (center, zoom, options) {
        this.map.setView(center, zoom, options)
    }

    /**
         * @description 将LayerId保存下来
         * @param {String} key
         * @param {Number} layerId
         */
    put (key, layerId) {
        this.store.set(key, layerId)
    }

    /**
     * @description 飞到某个点
     * @param {LatLng} center
     * @param {Number} zoom
     * @param {Object} options
     */
    flyTo (center, zoom, options) {
        this.map.flyTo(center, zoom, options)
    }

    /**
     * @description 获取地图
     * @returns Map实体
     */
    getMap () {
        return this.map
    }

    /**
     * @description 销毁地图
     */
    destroy () {
        this.map.remove()
    }

    /**
     * @description 注册监听
     * @param {String} name
     * @param {Function} fn
     * @param {Object} context
     */
    on (name, fn, context = this.map) {
        context.addEventListener(name, fn)
    }

    /**
     * @description 移除监听
     * @param {string} name
     * @param {Function} fn
     * @param {Object} context
     */
    off (name, fn, context = this.map) {
        context.removeEventListener(name, fn)
    }

    /**
     * @description 触发事件
     * @param {String} name
     * @param  {...any} args
     */
    emit (name, ...args) {
        this.map.fire(name, args)
    }

    /**
     * @private method
     * @description 创建特征Layer组
     * @returns LayerGroup
     */
    _createFeatureGroup () {
        return featureGroup([])
    }

    /**
     * @private method
     * @description 创建Layer控制类
     * @returns Layer
     */
    _helpLayer () {
        return this.layer ? this.layer : (this.layer = new Layer())
    }

    /**
     * @private
     * @description 创建Marker标记类
     * @returns Marker
     */
    _helpMarker () {
        return this.marker ? this.marker : (this.marker = new Marker())
    }
}
